using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using NWrapper.Config;
using NWrapper.Entities;

namespace NWrapper
{
	/// <summary>
	/// Defines the implementation of a data repository by exposing various CRUD (create,
	/// read, update, delete) methods.
	/// </summary>
	public interface IRepository
	{
		/// <summary>
		/// Initializes the repository.
		/// </summary>
		/// <param name="settings">The settings used for initialization.</param>
		void Initialize(RepositorySettings settings);

		#region Retrieve
		/// <summary>
		/// Retrieves a collection of all records of a given type from the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <returns>A collection of objects.</returns>
		ICollection<T> Retrieve<T>();

		/// <summary>
		/// Retrieves a collection of records of a given type that match the given criteria.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="whereClause">The match criteria.</param>
		/// <returns>A collection of objects</returns>
		ICollection<T> Retrieve<T>(string whereClause);

		/// <summary>
		/// Retrieves a collection of records of a given type that match the given criteria, ordered by the given sort order.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="whereClause">The match criteria.</param>
		/// <param name="sortClause">The sort order.</param>
		/// <returns>A collection of objects</returns>
		ICollection<T> Retrieve<T>(string whereClause, string sortClause);

		/// <summary>
		/// Retrieves a collection of records of a given type that match the given criteria, ordered by the given sort order.
		/// The subset uses the given start index and number of rows after sorting.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="whereClause">The match criteria.</param>
		/// <param name="sortClause">The sort order.</param>
		/// <param name="startRowIndex">The first row to retrieve.</param>
		/// <param name="maximumRows">The maximum number of rows to retrieve.</param>
		/// <returns>A collection of objects</returns>
		ICollection<T> Retrieve<T>(string whereClause, string sortClause, int startRowIndex, int maximumRows);
		#endregion

		#region RetrieveFirst
		/// <summary>
		/// Retrieves the first record of a given type from the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <returns>The object retrieved, or null if none.</returns>
		T RetrieveFirst<T>();

		/// <summary>
		/// Retrieves the first record of a given type from the repository that matches the given criteria.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="whereClause">The match criteria.</param>
		/// <returns>The object retrieved, or null if none.</returns>
		T RetrieveFirst<T>(string whereClause);

		/// <summary>
		/// Retrieves the first record of a given type from the repository that matches the given criteria.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="whereClause">The match criteria.</param>
		/// <param name="sortClause">The sort order.</param>
		/// <returns>The object retrieved, or null if none.</returns>
		T RetrieveFirst<T>(string whereClause, string sortClause);
		#endregion

		#region RetrievePage
		/// <summary>
		/// Retrieves collection of records of a given type from the repository, using a given page size and index.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="pageSize">The size of each page.</param>
		/// <param name="pageIndex">The page number to retrieve.</param>
		/// <returns>A collection of objects</returns>
		ICollection<T> RetrievePage<T>(int pageSize, int pageIndex);

		/// <summary>
		/// Retrieves collection of records of a given type from the repository, using a given page size and index.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="sortClause">The sort order.</param>
		/// <param name="pageSize">The size of each page.</param>
		/// <param name="pageIndex">The page number to retrieve.</param>
		/// <returns>A collection of objects</returns>
		ICollection<T> RetrievePage<T>(string sortClause, int pageSize, int pageIndex);

		/// <summary>
		/// Retrieves collection of records of a given type from the repository, using a given page size and index.
		/// </summary>
		/// <typeparam name="T">The type of object to retrieve.</typeparam>
		/// <param name="whereClause">The match criteria.</param>
		/// <param name="sortClause">The sort order.</param>
		/// <param name="pageSize">The size of each page.</param>
		/// <param name="pageIndex">The page number to retrieve.</param>
		/// <returns>A collection of objects</returns>
		ICollection<T> RetrievePage<T>(string whereClause, string sortClause, int pageSize, int pageIndex);
		#endregion

		#region Save
		/// <summary>
		/// Saves an object to the repository.
		/// </summary>
		/// <typeparam name="T">The type of object.</typeparam>
		/// <param name="instance">The object to save.</param>
		void Save<T>(T instance);

		/// <summary>
		/// Saves an object to the repository.
		/// </summary>
		/// <typeparam name="T">The type of object.</typeparam>
		/// <param name="instance">The object to save.</param>
		/// <param name="includeChildren">Specify true to recursively save all child objects.</param>
		void Save<T>(T instance, bool includeChildren);

		/// <summary>
		/// Saves a collection of objects to the repository.
		/// </summary>
		/// <typeparam name="T">The type of object.</typeparam>
		/// <param name="instances">The collection of objects to save.</param>
		void Save<T>(IEnumerable<T> instances);

		/// <summary>
		/// Saves a collection of objects to the repository.
		/// </summary>
		/// <typeparam name="T">The type of object.</typeparam>
		/// <param name="instances">The collection of objects to save.</param>
		/// <param name="includeChildren">Specify true to recursively save all child objects.</param>
		void Save<T>(IEnumerable<T> instances, bool includeChildren);
		#endregion

		#region Delete
		/// <summary>
		/// Deletes an object from the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to delete.</typeparam>
		/// <param name="instance">The object to delete.</param>
		void Delete<T>(T instance);

		/// <summary>
		/// Deletes a collection of objects from the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to delete.</typeparam>
		/// <param name="instances">The collection of objects to delete.</param>
		void Delete<T>(IEnumerable<T> instances);

		/// <summary>
		/// Deletes objects from the repository using the given criteria.
		/// </summary>
		/// <typeparam name="T">The type of object to delete.</typeparam>
		/// <param name="whereClause">The criteria specifying objects to delete.</param>
		/// <returns>The number of objects deleted.</returns>
		int Delete<T>(string whereClause);
		#endregion

		#region Insert
		/// <summary>
		/// Inserts a new object into the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to insert.</typeparam>
		/// <param name="instance">The object to insert.</param>
		void Insert<T>(T instance);
		#endregion

		#region Resync
		/// <summary>
		/// Reloads an object from the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to resync.</typeparam>
		/// <param name="obj">The object to resync.</param>
		/// <returns>The resynced object.</returns>
		T Resync<T>(T obj);
		#endregion

		#region GetObjectCount
		/// <summary>
		/// Gets the total number of objects of a given type that exist in the repository.
		/// </summary>
		/// <typeparam name="T">The type of object to count.</typeparam>
		/// <returns>The number of objects.</returns>
		int GetObjectCount<T>();
		#endregion
	}
}
